<?php
namespace App\Libs;
//封装单例模式（三私一公）
use App\Modules\Doctor\Services\DoctorService;

class SwooleWebSocket
{
    private static $instance;       //存放当前对象属性
    private static $server;         //存放webSocket对象属性

    //private $dir = storage_path('swoole.log');

    private function __construct() {
        //创建webSocket对象
        self::$server = new \Swoole\WebSocket\Server('0.0.0.0', 8877);
        //设置参数
        self::$server->set([
            'daemonize'     => 1,               // 作为守护进程运行，需同时设置log_file
            'log_file'      => storage_path('swoole.log'),//$this->dir,      // 指定标准输出和错误日志文件
        ]);
        //注册事件
        self::$server->on('open',[$this,'onOpen']);           //将当前类中的onOpen方法作为open的事件处理函数
        self::$server->on('message',[$this,'onMessage']);
        self::$server->on('close',[$this,'onClose']);
    }

    private function __clone() {
        // TODO: Implement __clone() method.
        trigger_error('Clone is not allowed !');
    }

    public static function getInstance() {
        if ( !(self::$instance instanceof self) ){
            self::$instance = new self();
        }
        return self::$instance;
    }

    //当前客户端连接之后要执行的方法
    public function onOpen($server,$request) {
        /*echo "client: {$request->fd}\n";
        $server->push($request->fd, "hello, welcome\n");*/
        $server->push($request->fd,['code'=>0,'msg'=>'']);
    }

    //当客户端向服务器发送消息时要执行的方法
    public function onMessage($server,$frame) {
        //处理业务逻辑
        //echo "client: {$frame->data}\n";
        $data = json_decode($frame->data,true);
        if($data==false) {
            $server->push($frame->fd, json_encode(['code'=>1000,'msg'=>'请求数据格式非法']));
        }
        if(self::validate_req_data($data)==false) {
            $server->push($frame->fd, json_encode(['code'=>1001,'msg'=>'请求参数有误']));
        }
        $uid = \Hashids::decode(array_get($data,'sid'))[0];
        if(empty($uid)) {
            $server->push($frame->fd, json_encode(['code'=>1001,'msg'=>'请求参数有误']));
        }
        if(array_get($data,'action') == 'bind') {
            \Redis::hMset('WebSocketUserFdId:'.$frame->fd,['uid'=>$uid,'utype'=>$data['utype']]);
            \Redis::hMset('WebSocketUserIdFd:'.$uid,['fd'=>$frame->fd,'utype'=>$data['utype']]);
            if($data['utype']=='doc') {
                \Redis::sAdd('WebSocketOnlineDoctorIds',$uid);
                $doctor_ids = \Redis::sMembers('WebSocketOnlineDoctorIds');

            }
        }
    }
    //当客户端和服务端断开连接时要执行的方法
    public function onClose($server,$fd) {
        echo "client-{$fd} is closed\n";
    }

    //启动webSocket方法
    public static function start(){
        self::$server->start();
    }

    private static function validate_req_data($data) {
        if(!is_array($data)) {
            return false;
        }
        if(!array_key_exists('action',$data)||
           !array_key_exists('sid',$data)||
           !array_key_exists('utype',$data)
        ) {
            return false;
        }
        if(!in_array($data['action'],['bind','call_video'])||
            !in_array($data['utype'],['doc','nor']) //doc 医生 nor 普通用户
        ) {
            return false;
        }
    }
}

//SwooleWebSocket::getInstance()->start();




//面向过程
////创建WebSocket Server对象，监听0.0.0.0:9502端口
//$ws = new Swoole\WebSocket\Server('0.0.0.0', 9505);
//
//$dir = 'swooleLogs/swoole.log';
//
//
////$ws->set(array(
////    'daemonize'     => 1,                       // 作为守护进程运行，需同时设置log_file
////    'log_file'      => $dir,  // 指定标准输出和错误日志文件
////));
//
////监听WebSocket连接打开事件
//$ws->on('open', function ($ws, $request) {
//    var_dump($request->fd, $request->server);
//    $ws->push($request->fd, "hello, welcome\n");
//});
//
////监听WebSocket消息事件
//$ws->on('message', function ($ws, $frame) {
//    echo "Message: {$frame->data}\n";
//    sleep(6);
//    $ws->push($frame->fd, "server: {$frame->data}");
//});
//
////监听WebSocket连接关闭事件
//$ws->on('close', function ($ws, $fd) {
//    echo "client-{$fd} is closed\n";
//});
//
//$ws->start();